package main

import (
	"encoding/json"
	"fmt"
	"my_code/biligoo/other"
	"sort"
	"strconv"
	"sync"
	"time"

	"github.com/bitly/go-simplejson"
	"github.com/gorilla/websocket"
)

type monitorInfo struct {
	Conn     *websocket.Conn
	MaxRoom  int
	Rooms    []int
	del      []int
	add      []int
	runs     int
	not_runs int
}

var (
	monitorInfos     = map[string]monitorInfo{}
	monitorInfosLock sync.RWMutex
)

func init() {
	fmt.Println(other.TI())
	// monitorInfos["2222"] = monitorInfo{nil, 2, []int{}, []int{}, []int{}}
	// monitorInfos["3333"] = monitorInfo{nil, 3, []int{}, []int{}, []int{}}
	// monitorInfos["4444"] = monitorInfo{nil, 4, []int{}, []int{}, []int{}}
	if true {
		go rooms() //抱枕
	}
	go func() {
		lastRoomNum := 0
		for {
			time.Sleep(time.Second * 30)
			maxRoom := 0

			monitorInfosLock.RLock()
			for _, monitor := range monitorInfos {
				maxRoom += monitor.MaxRoom
			}
			monitorInfosLock.RUnlock()

			roomids := getRooms(maxRoom) //[roomid,online]
			//fmt.Println("房间排序后:", roomids)
			if len(roomids) == 0 {
				continue
			}
			if len(roomids) < lastRoomNum/2 {
				continue
			}
			lastRoomNum = len(roomids)
			roomidsMap := make(map[int]int)
			AllroomidsMap := make(map[int]int)
			for _, num := range roomids {
				roomidsMap[num[0]] = num[1]
				AllroomidsMap[num[0]] = num[1]
			}

			monitorInfosLock.Lock()
			for name, monitor := range monitorInfos {
				for _, room := range monitor.Rooms {
					if _, have := roomidsMap[room]; have {
						delete(roomidsMap, room)
					} else {
						monitor.del = append(monitor.del, room)
					}
				}
				monitorInfos[name] = monitor
			}
			//fmt.Println("在线房间还要分配", len(roomidsMap))

			// 将 monitorInfos 转换为可排序的切片
			var sortableInfos []monitorInfo
			for _, info := range monitorInfos {
				sortableInfos = append(sortableInfos, info)
			}

			// 定义排序函数
			sortFunc := func(i, j int) bool {
				info1 := sortableInfos[i]
				info2 := sortableInfos[j]

				count1 := info1.MaxRoom - len(info1.Rooms) + len(info1.del)
				count2 := info2.MaxRoom - len(info2.Rooms) + len(info2.del)

				return count1 > count2
			}
			// 定义排序函数
			sortFunc = func(i, j int) bool {
				info1 := sortableInfos[i]
				info2 := sortableInfos[j]

				count1 := info1.MaxRoom
				count2 := info2.MaxRoom

				return count1 < count2
			}
			// 使用排序函数进行排序
			sort.Slice(sortableInfos, sortFunc)
			//fmt.Println("monitorInfo排序后：", sortableInfos)
			// 输出排序后的结果
			num := 0
		R:
			for _, roomInfo := range roomids {
				room, _ := roomInfo[0], roomInfo[1]
				_, have := roomidsMap[room]
				if !have {
					continue
				}
				num++
				for _ = range sortableInfos {
					monitorK := num % len(sortableInfos)
					monitor := sortableInfos[monitorK]
					if len(monitor.Rooms)-len(monitor.del)+len(monitor.add) < monitor.MaxRoom {
						monitor.add = append(monitor.add, room)
						delete(roomidsMap, room)
						sortableInfos[monitorK] = monitor
						continue R
					}
					num++
				}

			}

			for _, monitor := range sortableInfos {
				name := monitor.Conn.RemoteAddr().String()
				monitor.Rooms = sliceDelAdd(monitor.Rooms, monitor.del, monitor.add)
				fmt.Printf("%v监控 %v 删%v 增%v 总%v\n", other.TI(), name, len(monitor.del), len(monitor.add), len(monitor.Rooms))
				monitor.del = []int{}
				monitor.add = []int{}
				monitorInfos[name] = monitor
				monitorRooms := [][2]int{}

				for _, room := range monitor.Rooms {
					monitorRooms = append(monitorRooms, [2]int{room, AllroomidsMap[room]})
					//fmt.Println(" ", [2]int{room, AllroomidsMap[room]})
				}
				type IntSlices struct {
					Room [][2]int `json:"roomids"`
				}
				intSlices := IntSlices{
					Room: monitorRooms,
				}
				jsonData, err := json.Marshal(intSlices)
				if err != nil {
					fmt.Println("转换为JSON时发生错误:", err)
					continue
				}
				//fmt.Println(monitorRooms)
				//fmt.Println(string(jsonData))
				writeMessage(monitor.Conn, jsonData)
			}
			/*
				for _, monitor := range sortableInfos {
					name := monitor.Conn.RemoteAddr().String()
					// }

					// for name, monitor := range monitorInfos {
					//fmt.Println("监控", name, "已删除", len(monitor.del))
					for room := range roomidsMap {
						if len(monitor.Rooms)-len(monitor.del)+len(monitor.add) < monitor.MaxRoom {
							monitor.add = append(monitor.add, room)
							delete(roomidsMap, room)
						}
					}
					//fmt.Println("监控", name, "已增加", len(monitor.add))
					monitor.Rooms = sliceDelAdd(monitor.Rooms, monitor.del, monitor.add)
					fmt.Printf("%v监控 %v 删%v 增%v 总%v\n", other.TI(), name, len(monitor.del), len(monitor.add), len(monitor.Rooms))
					monitor.del = []int{}
					monitor.add = []int{}
					monitorInfos[name] = monitor

					// type IntSlices struct {
					// 	Room []int `json:"roomids"`
					// }
					// intSlices := IntSlices{
					// 	Room: monitor.Rooms,
					// }
					// jsonData, err := json.Marshal(intSlices)
					// if err != nil {
					// 	fmt.Println("转换为JSON时发生错误:", err)
					// 	continue
					// }

					if true {
						monitorRooms := [][2]int{}
						for _, room := range monitor.Rooms {
							monitorRooms = append(monitorRooms, [2]int{room, AllroomidsMap[room]})
						}
						type IntSlices struct {
							Room [][2]int `json:"roomids"`
						}
						intSlices := IntSlices{
							Room: monitorRooms,
						}
						jsonData, err := json.Marshal(intSlices)
						if err != nil {
							fmt.Println("转换为JSON时发生错误:", err)
							continue
						}
						//fmt.Println(monitorRooms)
						//fmt.Println(string(jsonData))
						writeMessage(monitor.Conn, jsonData)
					}

				}
				//*/
			monitorInfosLock.Unlock()

		}
	}()
}
func sliceDelAdd(slice, del, add []int) []int {
	var result []int
	for _, valA := range slice {
		found := false
		for _, valB := range del {
			if valA == valB {
				found = true
				break
			}
		}
		if !found {
			result = append(result, valA)
		}
	}
	result = append(result, add...)
	return result
}

func getRooms(maxRoom int) (roomids [][2]int) {
	roomEndTimeLock.Lock()
	defer roomEndTimeLock.Unlock()
	roomids0 := sortRoom(roomEndTime)
	if len(roomids0) > maxRoom {
		roomids = roomids0[:maxRoom]
	} else {
		roomids = roomids0
	}
	return
}

func sortRoom(roomEndTime map[int][2]int) [][2]int {
	type RoomEntry struct {
		roomid    int
		timestamp int
		pages     int
	}

	// 将roomEndTime的每个条目转换为结构体实例，并存储在切片entries中
	entries := make([]RoomEntry, 0, len(roomEndTime))
	for roomid, value := range roomEndTime {
		entry := RoomEntry{
			roomid:    roomid,
			timestamp: value[0],
			pages:     value[1],
		}
		entries = append(entries, entry)
	}

	// 使用sort.Slice函数对切片entries进行排序，根据页数进行比较
	sort.Slice(entries, func(i, j int) bool {
		return entries[i].pages > entries[j].pages
	})

	// 创建一个新的切片，只包含排序后的roomid
	sortedRoomIDs := make([][2]int, len(entries))
	for i, entry := range entries {
		sortedRoomIDs[i] = [2]int{entry.roomid, entry.pages}
	}

	// 输出排序后的roomid切片
	return sortedRoomIDs
}

var (
	roomEndTime     = map[int][2]int{} //roomid:[时间戳，在线人数]
	roomEndTimeLock = sync.Mutex{}
)

func rooms() {
	for {
		if false {
			//rs := areaList0() // 这个会返回(roomids []int)

		}
		//rs := getBaoZhenRoom() //抱枕
		rs := areaList0()
		rs_bz := getBaoZhenRoom() //抱枕
		roomEndTimeLock.Lock()

		currentTimestamp := int(time.Now().Unix())
		last := len(roomEndTime)
		// 将rs所有值作为键存入roomEndTime，值为当前时间戳+300
		for _, r := range rs {
			roomEndTime[r[0]] = [2]int{currentTimestamp + 300, r[1]}
		}
		for _, r := range rs_bz {
			roomEndTime[r[0]] = [2]int{currentTimestamp + 300, r[1]}
		}
		delNum := 0
		// 删除roomEndTime中值小于当前时间戳的键
		for r, endTime := range roomEndTime {
			if endTime[0] < currentTimestamp {
				delNum++
				delete(roomEndTime, r)
			}
		}
		//last - delNum + addNum = len(roomEndTime)
		//fmt.Printf("%v在线房间更新:%v - %v + %v = %v ", other.TI(), last, delNum, len(roomEndTime)-last+delNum, len(roomEndTime))
		fmt.Printf("%v在线房间增%v 删%v 总%v      \n", other.TI(), len(roomEndTime)-last+delNum, delNum, len(roomEndTime))
		roomEndTimeLock.Unlock()
		time.Sleep(time.Second * 30)
	}
}

// roomids, [2]int{roomid, online}
func areaList0() (roomids [][2]int) {
	roomids = [][2]int{}

	runs := []string{"-", "\\", "|", "/"}
	for page := 1; page <= 2000; page++ {
		fmt.Printf("\r%v正在查询第%v页，已获得%v个房间      ", runs[page%len(runs)], page, len(roomids))
		url := "https://api.live.bilibili.com/xlive/web-interface/v1/second/getList?platform=web&parent_area_id=3&area_id=321&sort_type=sort_type_282&page=" + strconv.Itoa(page) //原神分区
		url = "https://api.live.bilibili.com/xlive/web-interface/v1/second/getUserRecommend?page_size=30&platform=web&page=" + strconv.Itoa(page)
		//https://api.live.bilibili.com/xlive/web-interface/v1/second/getUserRecommend?page=1&page_size=30&platform=web
		//https://api.live.bilibili.com/xlive/web-interface/v1/second/getList?platform=web&parent_area_id=3&area_id=321&sort_type=sort_type_282&page=1
		//原神分区
		b, c := other.AppReqGet(url)
		if !c {
			return
		}
		//fmt.Println(url, "\n", string(b))
		js, err := simplejson.NewJson(b)
		if err != nil {
			return
		}
		//[0].roomid
		list, err := js.Get("data").Get("list").Array()
		if err != nil {
			fmt.Println("getRoomid json data err:", err)
			return
		}
		if len(list) == 0 {
			break
		}
		for i := range list {

			roomid, err := js.Get("data").Get("list").GetIndex(i).Get("roomid").Int()
			if err != nil {
				fmt.Println("getRoomid json data.x.roomid err:", err)
				return
			}
			// uid, err := js.Get("data").Get("list").GetIndex(i).Get("uid").Int()
			// if err != nil {
			// 	fmt.Println("getRoomid json data.x.roomid err:", err)
			// 	return
			// }
			online, err := js.Get("data").Get("list").GetIndex(i).Get("watched_show").Get("num").Int()
			if err != nil {
				fmt.Println("getRoomid json data.x.roomid err:", err)
				return
			}
			online = -((page-1)*30 + i + 1)
			roomids = append(roomids, [2]int{roomid, online})
		}
		has_more, err := js.Get("data").Get("has_more").Int()
		if err == nil && has_more == 0 {
			break
		}
		//time.Sleep(time.Second / 10)
	}
	//fmt.Println(roomids)
	return
}

// [roomid,online]
func areaList() (roomids [][2]int) {
	roomids = [][2]int{}
	mu := sync.Mutex{}
	uri := "https://api.live.bilibili.com/room/v1/Area/getList"
	b, c := other.AppReqGet(uri)
	if !c {
		return
	}
	//fmt.Println(string(b))
	js, err := simplejson.NewJson(b)
	if err != nil {
		return
	}
	//[0].roomid
	list, err := js.Get("data").Array()
	if err != nil {
		fmt.Println("getRoomid json data err:", err)
		return
	}
	wg := sync.WaitGroup{}
	for i := range list {
		id0, err := js.Get("data").GetIndex(i).Get("id").Int()
		if err != nil {
			fmt.Println("getRoomid json data.x.id err:", err)
			return
		}
		//fmt.Println(id0)

		list0, err := js.Get("data").GetIndex(i).Get("list").Array()
		if err != nil {
			fmt.Println("getRoomid json data.x.list err:", err)
			return
		}
		for ii := range list0 {
			id1, err := js.Get("data").GetIndex(i).Get("list").GetIndex(ii).Get("id").String()
			if err != nil {
				fmt.Println("getRoomid json data.x.list.xx.id err:", err)
				return
			}
			//fmt.Println("", id1)
			//https://api.live.bilibili.com/xlive/web-interface/v1/second/getList?platform=web&parent_area_id=2&area_id=86&sort_type=&page=1&vajra_business_key=
			wg.Add(1)
			go func(id0, id1 interface{}) {
				defer wg.Done()
				rs := areaRoomList(id0, id1)
				mu.Lock()
				roomids = append(roomids, rs...)
				mu.Unlock()

			}(id0, id1)
		}
	}
	wg.Wait()
	fmt.Printf("%v总计找到房间数目:%v ", other.TI(), len(roomids))
	return
}

func areaRoomList(parent_area_id, area_id interface{}) (roomids [][2]int) {
	roomids = [][2]int{}
	pageStart, pageEnd := 1, 999999
	runs := []string{"-", "\\", "|", "/"}
	wg := sync.WaitGroup{}
	mu := sync.Mutex{}

	n := 1
	for i := 0; i < n; i++ {
		wg.Add(1)
		go func(index int) {
			defer wg.Done()
			tempRoomIDs := [][2]int{}

			start := pageStart + index
			for page := start; page <= pageEnd; page += n {
				fmt.Printf("\r%v正在查询第%v页，已获得%v个房间 ", runs[page%len(runs)], page, len(tempRoomIDs))
				uri := fmt.Sprintf("https://api.live.bilibili.com/xlive/web-interface/v1/second/getList?platform=web&parent_area_id=%v&area_id=%v&sort_type=&page=%v&vajra_business_key=", parent_area_id, area_id, page)
				b, c := other.AppReqGet(uri)
				if !c {
					return
				}
				//fmt.Println(uri, "\n", string(b))
				js, err := simplejson.NewJson(b)
				if err != nil {
					return
				}
				//[0].roomid
				list, err := js.Get("data").Get("list").Array()
				if err != nil {
					fmt.Println("getRoomid json data.list err:", err)
					return
				}
				if len(list) == 0 {
					break
				}
				for i := range list {
					roomid, err := js.Get("data").Get("list").GetIndex(i).Get("roomid").Int()
					if err != nil {
						fmt.Println("getRoomid json data.x.roomid err:", err)
						return
					}
					// uid, err := js.Get("data").Get("list").GetIndex(i).Get("uid").Int()
					// if err != nil {
					// 	fmt.Println("getRoomid json data.x.uid err:", err)
					// 	return
					// }
					// if fmt.Sprintf("%v", area_id) == "321" {
					// 	like2(roomid, uid)
					// }
					//data.list[0].online
					online, err := js.Get("data").Get("list").GetIndex(i).Get("online").Int()
					if err != nil {
						fmt.Println("getRoomid json data.x.online err:", err)
						return
					}
					tempRoomIDs = append(tempRoomIDs, [2]int{roomid, online})
				}
			}
			//if page == pageEnd {
			//}

			mu.Lock()
			roomids = append(roomids, tempRoomIDs...)
			//fmt.Println("roomid存入", len(tempRoomIDs))
			mu.Unlock()
		}(i)
	}

	wg.Wait()

	fmt.Printf("\r%v从分区%v.%v中找到%v个房间 ", other.TI(), parent_area_id, area_id, len(roomids))

	return roomids
}

// 抱枕
func getBaoZhenRoom() (roomids [][2]int) {
	roomids = [][2]int{}
	uri := "https://api.live.bilibili.com/xlive/fuxi-interface/RedPacketHourController/getInfo?_ts_rpc_args_=[104175,10988]"
	b, c := other.AppReqGet(uri)
	if !c {
		fmt.Println(c, 1)
		return
	}
	js, err := simplejson.NewJson(b)
	if err != nil {
		fmt.Println(err, 2)
		return
	}
	//_ts_rpc_return_.data.timestamp
	timestamp, err := js.Get("_ts_rpc_return_").Get("data").Get("timestamp").Int()
	if err != nil {
		fmt.Println(err, 3)
		return
	}
	for page := 0; page < 21; page++ {
		//https://api.live.bilibili.com/xlive/fuxi-interface/RankingController/getRanking?_ts_rpc_args_=[%7B%22id%22:13061,%22type%22:1,%22cursor%22:0,%22length%22:20,%22actId%22:105742,%22timeDimensionType%22:1,%22timeDimensionValue%22:1716462436000,%22roomId%22:0%7D]
		//id: 13061
		//actId: 105742
		id := "13061"
		actId := "105742"
		//uri = "https://api.live.bilibili.com/xlive/fuxi-interface/RankingController/getRanking?_ts_rpc_args_=[%7B%22id%22:" + id + ",%22type%22:1,%22cursor%22:" + strconv.Itoa(page*50) + ",%22length%22:50,%22actId%22:" + actId + ",%22timeDimensionType%22:1,%22timeDimensionValue%22:" + strconv.Itoa(timestamp) + ",%22roomId%22:22388070,%22personalInfoType%22:1%7D]" //20231206
		uri = "https://api.live.bilibili.com/xlive/fuxi-interface/RankingController/getRanking?_ts_rpc_args_=[%7B%22id%22:" + id + ",%22type%22:1,%22cursor%22:" + strconv.Itoa(page*50) + ",%22length%22:50,%22actId%22:" + actId + ",%22timeDimensionType%22:1,%22timeDimensionValue%22:" + strconv.Itoa(timestamp) + ",%22roomId%22:0%7D]" //20231206
		//_ts_rpc_return_.data.list[1].uid
		b, c = other.AppReqGet(uri)
		if !c {
			fmt.Println(c, 4)
			return
		}
		js, err = simplejson.NewJson(b)
		if err != nil {
			fmt.Println(err, 5)
			return
		}
		list, err := js.Get("_ts_rpc_return_").Get("data").Get("list").Array()
		if err != nil {
			fmt.Println(err, 6)
			return
		}
		if len(list) == 0 {
			fmt.Println(err, 61, page)
			return
		}
		uids := []string{}
		uidScore := map[string]string{}
		for k := range list {
			uid, err := js.Get("_ts_rpc_return_").Get("data").Get("list").GetIndex(k).Get("uid").String()
			if err != nil {
				fmt.Println(err, 7)
				return
			}
			score, err := js.Get("_ts_rpc_return_").Get("data").Get("list").GetIndex(k).Get("score").String()
			if err != nil {
				fmt.Println(err, 71)
				return
			}
			uidScore[uid] = score
			uids = append(uids, uid)
		}
		suids := ""
		for k, uid := range uids {
			suids = suids + uid
			if k != len(uids)-1 {
				suids = suids + ","
			}
		}
		uri = "https://api.live.bilibili.com/xlive/fuxi-interface/UserService/getUserInfo?_ts_rpc_args_=[[" + suids + "],true,%22%22]"
		b, c = other.AppReqGet(uri)
		if !c {
			fmt.Println(c, 8)
			return
		}
		js, err = simplejson.NewJson(b)
		if err != nil {
			fmt.Println(err, 9)
			return
		}
		//fmt.Println(string(b))
		//_ts_rpc_return_.data[3546567638255656].roomId
		for _, uid := range uids {
			roomid, err := js.Get("_ts_rpc_return_").Get("data").Get(uid).Get("roomId").String()
			if err != nil {
				fmt.Println(err, 10)
				return
			}
			//fmt.Println(k, uid, ":", roomid)
			iroomid, _ := strconv.Atoi(roomid)
			score, _ := strconv.Atoi(uidScore[uid])
			roomids = append(roomids, [2]int{iroomid, score})
		}
	}
	//fmt.Println(roomids)
	fmt.Printf("%v抱枕-房间获取到%v个 \n", other.TI(), len(roomids))
	return
}
